package com.shop.shoppingmall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.beust.jcommander.internal.Maps;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.shop.shoppingmall.dao.*;
import com.shop.shoppingmall.entity.*;
import com.shop.shoppingmall.service.ShOrderService;
import com.shop.shoppingmall.util.*;
import com.shop.shoppingmall.util.api.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 订单表(ShOrder)表服务实现类
 *
 * @author makejava
 * @since 2020-10-12 15:33:34
 */
@Service("shOrderService")
@Slf4j
@Transactional
public class ShOrderServiceImpl implements ShOrderService {
    @Resource
    private ShOrderDao shOrderDao;
    @Resource
    private ShUserDao shUserDao;
    @Resource
    private ShWalletDao shWalletDao;
    @Resource
    private ShOrderAllDao shOrderAllDao;
    @Resource
    private ShDayCoinDao shDayCoinDao;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Resource
    private ShBackUserDao shBackUserDao;
    @Resource
    private ShRechargeDao shRechargeDao;

    private final String PROJECT_SERVER_URL ="http://www.xzrenli.com/shop/shOrder/wxpayNotify";

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public ShOrder queryById(String id) {
        return this.shOrderDao.queryById(id);
    }

    /**
     * 新增数据
     *
     * @param / 实例对象
     * @return 实例对象
     */
    @Override
    public Result insertOrder(ShOrder shOrder) {
        shOrder.setId(UUIDGenerator.generate());
        String salt = oConvertUtils.randomGen(16);
        shOrder.setOrderNumber(salt);
        shOrder.setOrderStatus("0");
        shOrderDao.insert(shOrder);
        return Result.ok(shOrder);
    }

    /**
     * 用户购买商品确认订单
     * @param
     * @return
     */
    @Override
    public Result confirmOrder(List<OrderEntity> categorylist, Integer sumPrice, Integer sums, ShWallet shWallet) {
        Map map1 = new HashMap();
        List<OrderEntity> orderEntityList =  shOrderDao.queryByspecId(categorylist);
        BigDecimal sumPrice1 = new BigDecimal(0);
        if(categorylist.size()>1){
            Integer num=null ;
            for(int i= 0;i<categorylist.size();i++){
                num=  categorylist.get(i).getNum();
                for(OrderEntity orderEntity : orderEntityList){
                    if(orderEntity.getId().equals(categorylist.get(i).getId())){
                        orderEntity.setNum(num);
                        orderEntity.setProductPrice(orderEntity.getProductPrice().add(orderEntity.getRebatePrice()));
                    BigDecimal aa = orderEntity.getProductPrice();
                    log.info("金额计算,单个商品"+aa+"数量"+num);
                        log.info("==========="+sumPrice1);
                        sumPrice1=   sumPrice1.add(aa.multiply(new BigDecimal(num)));
                    }

                }
            }
            map1.put("orderEntityList",orderEntityList);
            map1.put("sumPrice",sumPrice1);
            map1.put("sums",sums);
            map1.put("dayCoin",shWallet.getDayCoin());
            System.out.println(orderEntityList);
            return Result.ok(map1);
        }else{
            Integer num=null ;
            for(int i= 0;i<categorylist.size();i++){
                num=  categorylist.get(i).getNum();
                orderEntityList.get(i).setNum(num);
                orderEntityList.get(i).setProductPrice(orderEntityList.get(i).getProductPrice().add(orderEntityList.get(i).getRebatePrice()));
                BigDecimal aa = orderEntityList.get(i).getProductPrice();
                log.info("金额计算,单个商品"+aa+"数量"+num);
                log.info("dfdsfdsfdsf"+sumPrice1);
                sumPrice1= sumPrice1.add(aa.multiply(new BigDecimal(num)));
            }
            map1.put("orderEntityList",orderEntityList);
            map1.put("sumPrice",sumPrice1);
            map1.put("sums",sums);
            map1.put("dayCoin",shWallet.getDayCoin());
            return  Result.ok(map1);
        }

    }

    /**
     * 修改数据
     *
     * @param shOrder 实例对象
     * @return 实例对象
     */
    @Override
    public ShOrder update(ShOrder shOrder) {
        this.shOrderDao.update(shOrder);
        return this.queryById(shOrder.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return this.shOrderDao.deleteById(id) > 0;
    }

    /**
     * 查询所有订单信息
     * @param map
     * @param
     * @return
     */
    @Override
    public Result queryAll(Map map) {
        Integer pagenum = (Integer) map.get("pagenum");
        Integer pagesize = (Integer) map.get("pagesize");
        int a = (pagenum-1)*pagesize;
        map.put("offset",a);
        map.put("limit",pagesize);
        List<ShOrder> shOrders = shOrderDao.queryAll(map);
        if(shOrders == null){
            return Result.error("暂时还没有订单信息");
        }
        ShOrder shOrder = shOrderDao.queryCount(map);
        Map map1 = new HashMap();
        map1.put("total", shOrder.getTotal());
        map1.put("shOrders",shOrders);
        return Result.ok(map1);
    }

    /**
     * 店铺查询根据merchantId查询该店铺的所有订单
     * merchantId  必传
     * @param map
     * @return
     */
    @Override
    public Result queryMerchant(Map map) {
        String merchantid = map.get("merchantId").toString();
        if(merchantid ==null && merchantid.equals("")){
            return Result.error("店铺id不能为空");
        }
        Integer pagenum = (Integer) map.get("pagenum");
        Integer pagesize = (Integer) map.get("pagesize");
        int a = (pagenum-1)*pagesize;
        System.out.println(a);
        map.put("offset",a);
        map.put("limit",pagesize);
        List<ShOrder> shOrders = shOrderDao.queryAll(map);
        if(shOrders == null){
            return Result.error("暂时还没有订单信息");
        }
        ShOrder shOrder = shOrderDao.queryCount(map);
        Map map1 = new HashMap();
        map1.put("total", shOrder.getTotal());
        map1.put("shOrders",shOrders);
        return Result.ok(map1);
    }


    /**
     * 下订单
     * @param
     * @param
     * @return
     * List<ShOrder> shOrders
     */
    @Override
    public Result insertOrderAll(HttpServletRequest request,String jsonRequest) {
        //解析token，拿到userId
        String idAll = UUIDGenerator.generate();
        String name = JwtUtil.getUserNameByToken(request);
        ShUser shUser = shUserDao.selectLoginName(name);
        if(StringUtils.isBlank(name) || null == shUser){
            return Result.error(CommonConstant.SC_OK_201,"您还未注册或者登录，请先注册或登录");
        }
        String userId = shUser.getId();
        //接收总价格等参数
        JSONObject jsonObject = JSONObject.parseObject(jsonRequest);
        Map<String, Object> map =jsonObject;
        String category= map.get("categorylist").toString();
//        Integer priceAll = (Integer) map.get("sumPrice");
        String isKeep = (String) map.get("isKeep");
        Integer coinPrice = (Integer) map.get("coinPrice");
        String addId = (String) map.get("addId");
        String messages = (String) map.get("messages");
        List<OrderEntity> cateGoryList = JSONObject.parseArray(category,OrderEntity.class);
        List<OrderEntity> orderEntityList =  shOrderDao.queryByspecId(cateGoryList);
        //遍历集合拿到各个商品的数量
        BigDecimal priceAll = new BigDecimal(0);
        if(cateGoryList.size()>1) {
            Integer num = null;
            for (int i = 0; i < cateGoryList.size(); i++) {
                num = cateGoryList.get(i).getNum();
                //遍历集合，将信息set到相应的对象中
                for (OrderEntity orderEntity : orderEntityList) {
                    if (orderEntity.getId().equals(cateGoryList.get(i).getId())) {
                        orderEntity.setNum(num);
                        orderEntity.setOrderId(UUIDGenerator.generate());
                        orderEntity.setOrderNum(oConvertUtils.randomGen(16));
                        orderEntity.setUserId(userId);
                        orderEntity.setAddId(addId);
                        //判断前端传过来的iskeep参数，如果是0，没用折扣，直接将折扣价设为0
                        if(isKeep.equals(0)){
                            orderEntity.setCoinPrice(new BigDecimal(0));
                        }

                        //处理价格
                        orderEntity.setProductPrice(orderEntity.getProductPrice().add(orderEntity.getRebatePrice()));
                        BigDecimal productPrice = orderEntity.getProductPrice();
                        BigDecimal multiply = productPrice.multiply(new BigDecimal(num));

                        priceAll=priceAll.add(multiply);
                        orderEntity.setReallyPrice(multiply);
                        orderEntity.setOrderStatus("1");
                        orderEntity.setOrderType("0");
                        orderEntity.setOrderAllId(idAll);
                        orderEntity.setMessages(messages);
                    }
                }
            }
            //判断前端传过来的iskeep参数，如果是1，用户选择用馨天币作为折扣抵价
            if(isKeep.equals("1")){
                BigDecimal productPrice = orderEntityList.get(0).getProductPrice();
                BigDecimal multiply = productPrice.multiply(new BigDecimal(orderEntityList.get(0).getNum()));
                BigDecimal subtract = multiply.subtract(new BigDecimal(coinPrice));
                orderEntityList.get(0).setCoinPrice(new BigDecimal(coinPrice));
                orderEntityList.get(0).setReallyPrice(subtract);
                shWalletDao.updateCoinDay(userId);
                //馨天币抵消后，作为一条明细信息，插入到馨天币明细表中
                ShDayCoin shDayCoin = new ShDayCoin();
                shDayCoin.setId(UUIDGenerator.generate());
                shDayCoin.setUserId(userId);
                shDayCoin.setIncome(new BigDecimal(0));
                shDayCoin.setExpenditure(new BigDecimal(coinPrice));
                shDayCoin.setType("2");
                shDayCoin.setDetail("抵消购买商品的部分价格！");
                shDayCoinDao.insert(shDayCoin);
            }
            shOrderDao.insertOrderList(orderEntityList);
            //多个订单，生成一个总的订单，插入到总订单的表格中

            ShOrderAll shOrderAll = new ShOrderAll();
            shOrderAll.setId(idAll);
            shOrderAll.setUserId(userId);
            shOrderAll.setOrderNumAll(oConvertUtils.randomGen(16));
            shOrderAll.setOrderPriceAll(priceAll);
            shOrderAll.setOrderStatus("1");
            shOrderAll.setOrderType("0");
            shOrderAllDao.insert(shOrderAll);

            //清除购物车记录
            log.info(orderEntityList+"===..>..,.,.,.,.,");
            for(int i=0;i<orderEntityList.size();i++){
                log.info("执行>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<");
                shOrderDao.deleteByUserIdAndSpecsId(userId,orderEntityList.get(i).getId());
            }
            //将总订单号和总价格放到map中，返回给前端
            Map<String,Object> map1 = new HashMap<>();
            map1.put("orderNumber",shOrderAll.getOrderNumAll());
            map1.put("price",priceAll);
            //设置redis
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set("orderNumber,"+shOrderAll.getOrderNumAll(), userId);
            redisTemplate.expire("orderNumber,"+shOrderAll.getOrderNumAll(), 30, TimeUnit.MINUTES);
            return Result.ok(map1);
        }else {
            Integer num = null;
            for (int i = 0; i < cateGoryList.size(); i++) {
                num = cateGoryList.get(i).getNum();
                for (OrderEntity orderEntity : orderEntityList) {
                    if (orderEntity.getId().equals(cateGoryList.get(i).getId())) {
                        orderEntity.setNum(num);
                        orderEntity.setOrderId(UUIDGenerator.generate());
                        orderEntity.setOrderNum(oConvertUtils.randomGen(16));
                        orderEntity.setUserId(userId);
                        orderEntity.setAddId(addId);
                        //设置价格
                        orderEntity.setProductPrice(orderEntity.getProductPrice().add(orderEntity.getRebatePrice()));
                        BigDecimal productPrice = orderEntity.getProductPrice();
                        BigDecimal multiply = productPrice.multiply(new BigDecimal(num));

                        orderEntity.setReallyPrice(multiply);
                        orderEntity.setOrderStatus("1");
                        orderEntity.setOrderType("0");
                        orderEntity.setOrderAllId("");
                        orderEntity.setMessages(messages);
                        if (isKeep.equals(0)) {
                            orderEntity.setCoinPrice(new BigDecimal(0));
                        }
                    }
                }
            }
            if(isKeep.equals("1")){
                BigDecimal productPrice = orderEntityList.get(0).getProductPrice();
                BigDecimal multiply = productPrice.multiply(new BigDecimal(num));
                BigDecimal subtract = multiply.subtract(new BigDecimal(coinPrice));
                orderEntityList.get(0).setProductPrice(subtract);
                orderEntityList.get(0).setCoinPrice(new BigDecimal(coinPrice));
                shWalletDao.updateCoinDay(userId);

                ShDayCoin shDayCoin = new ShDayCoin();
                shDayCoin.setId(UUIDGenerator.generate());
                shDayCoin.setUserId(userId);
                shDayCoin.setIncome(new BigDecimal(0));
                shDayCoin.setExpenditure(new BigDecimal(coinPrice));
                shDayCoin.setType("2");
                shDayCoin.setDetail("抵消购买商品的部分价格！");
                shDayCoinDao.insert(shDayCoin);
            }
            shOrderDao.insertOrderList(orderEntityList);
            Map<String,Object> map1 = new HashMap<>();
            map1.put("orderNumber",orderEntityList.get(0).getOrderNum());
            map1.put("price",priceAll);
            //设置redis
            ValueOperations<String, String> operations = redisTemplate.opsForValue();
            operations.set("orderNumber,"+orderEntityList.get(0).getOrderNum(), userId);
            redisTemplate.expire("orderNumber,"+orderEntityList.get(0).getOrderNum(), 30, TimeUnit.MINUTES);
            return Result.ok(map1);
        }
    }

    /**
     * 查询订单不同状态的数量
     * @param request
     * @return
     */
    @Override
    public Result selectShOrderStatus(HttpServletRequest request) {
        //解析token，拿到userId
        String name = JwtUtil.getUserNameByToken(request);
        ShUser shUser = shUserDao.selectLoginName(name);
        if(StringUtils.isBlank(name) || null == shUser){
            return Result.error(CommonConstant.SC_OK_201,"您还未注册或者登录，请先注册或登录");
        }
        String userId = shUser.getId();
        ShOrder shOrder = shOrderDao.selectOrderStatus(userId);
        if(shOrder == null){
            return Result.error("暂时还没有订单信息!");
        }
        return Result.ok(shOrder);
    }

    /**
     * 根据用户id查询订单
     * @param map
     * @return
     */
    @Override
    public Result queryUserId(Map map) {
        List<ShOrder> shOrders = shOrderDao.queryList(map);
//        for(ShOrder shOrder : shOrders){
//            shOrder.setOrderPrice(shOrder.getOrderPrice().add(shOrder.getRebatePrice()));
//        }
        return Result.ok(shOrders);
    }

    /**
     * 取消订单
     * @param orderNumber 订单号
     * @return
     */
    @Override
    public Result cancelOrder(String orderNumber) {
        ShOrder shOrder = shOrderDao.queryOrderNumber(orderNumber);
        if(shOrder != null){
            shOrder.setOrderStatus("5");
            shOrderDao.update(shOrder);
            return Result.ok("订单已取消");
        }else{
            return Result.error("未查询到该订单");
        }

    }

    @Override
    public Result selectAll() {
        List<ShOrder> shOrders = shOrderDao.selectAll();
        if(shOrders == null){
            return Result.error("暂时没有订单信息!");
        }
        return Result.ok(shOrders);
    }


    /**
     * 店铺处理代发货订单 修改状态保存快递单号
     * @param orderNumber 订单号
     * @param courierNum 快递单号
     * @return
     */
    @Override
    public Result updateState(String orderNumber,String courierNum) {
        if(courierNum ==null && courierNum.equals("")){
            return Result.error("快递单号不能为空");
        }
        ShOrder shOrder = shOrderDao.queryOrderNumber(orderNumber);
        if(shOrder == null){
            return Result.error("暂时没有订单信息!");
        }
        if(shOrder.getOrderStatus().equals("2")){
            shOrder.setCourierNum(courierNum);
            shOrder.setOrderStatus("3");
            shOrderDao.update(shOrder);
            return Result.ok("该订单已发货");
        }else{
            return Result.error("该状态订单不能修改");
        }
    }

    /**
     * @Function: 支付宝异步回调接口
     * @author: YangXueFeng
     * @Date: 2019/6/11 20:03
     */
    @Override
    public void appAliPayNotify(HttpServletRequest request) {

    }




    @Override
    public Map<String, Object> payRequest(String orderId) throws Exception {
        /**
         * 本处两个map,在代码上是不应该出现的,但是在调试的时候,遇见了坑,为了代码更
         * 清晰一点,就new 了两个Map,一个是加签使用,一个是返回给客户端使用.
         * newMap:返回给服务端的
         * newData:二次加签的
         **/
        ShOrder shOrder = shOrderDao.queryOrderNumber(orderId);
        Map<String,Object> newMap  = Maps.newHashMap();
        Map<String, String> newData = new HashMap<String, String>();
        TenpayConfig tenpayConfig = new TenpayConfig();
        //AppId:在微信开发平台就可以获取的
        tenpayConfig.setAppId("wx058fd83a5ba087f8");
        /**
         * Key:特别声明下,此处是个坑,官方文档也没有具体的描述,很多第一次使用的同学
         * 会直接使用开发平台的key,然后加签失败.该key需要登录商户平台进行设置的.
         * 一定一定要登录商户平台去设置哦,不是开发平台.
         **/
        tenpayConfig.setKey("shandongxintwangluokejiyouxiango");
        //商户号,商户平台可以获取
        tenpayConfig.setMchId("1604330053");
        //固定写死,不要问为什么,官方要求的
        tenpayConfig.setPackageValue("Sign=WXPay");
        MyPayConfig myPayConfig = new MyPayConfig(tenpayConfig);
        // WXPay是目前可以使用的官方jar.
        WXPay wxPay = new WXPay(myPayConfig);
        log.info("封装wxpay支付请求参数==================");
        // 开始第一次加签
        Map<String, String> paramsMap = new HashMap<>();
        //随机字符串
        String nonce_str = WXPayUtil.generateNonceStr();
        paramsMap.put("nonce_str", nonce_str);
        //描述

        if(shOrder == null){
            ShOrderAll shOrderAll = shOrderAllDao.selectByOrderAllNum(orderId);
            if(shOrderAll ==null){
                //充值会员
                ShRecharge shRecharge = shRechargeDao.selectRechargeOrderNumber(orderId);
                paramsMap.put("out_trade_no", shRecharge.getOrderNumber());
                log.info("微信支付 会员充值支付 =================订单号:{}",shRecharge.getOrderNumber());
                int price100 =(shRecharge.getOrderPrice().multiply(new BigDecimal(100))).intValue();
                paramsMap.put("total_fee", String.valueOf(price100));
                paramsMap.put("body", "馨T网会员充值");
            }else{
                //多个订单支付
                String orderNumAll = shOrderAll.getOrderNumAll();
                BigDecimal orderPriceAll = shOrderAll.getOrderPriceAll();
                // 商户订单号 就是商户后台生成的订单号
                paramsMap.put("out_trade_no", orderNumAll);
                log.info("微信支付 多条订单同时支付 =================订单号:{}",orderNumAll);
                int price100 =(orderPriceAll.multiply(new BigDecimal(100))).intValue();
                paramsMap.put("total_fee", String.valueOf(price100));
                paramsMap.put("body", "馨T网商品购买");
            }
        }else{
            //商户订单号(支付编号)
            //支付编号
            String orderNum = shOrder.getOrderNumber();
            paramsMap.put("out_trade_no", orderNum);
            log.info("微信支付 单个订单支付 =================订单号:{}",orderNum);
            //支付金额,金额单位为 分
            BigDecimal price = shOrder.getOrderPrice();
            int price100 =(shOrder.getReallyPrice().multiply(new BigDecimal(100))).intValue();
            paramsMap.put("total_fee", String.valueOf(price100));
            paramsMap.put("body", "馨T网商品购买");
        }
        //回调地址
        paramsMap.put("notify_url", PROJECT_SERVER_URL);
        //交易类型
        paramsMap.put("trade_type", "APP");
        //用户端ip
        String spbillCreateIp = "";
        InetAddress inetAddress = InetAddress.getLocalHost();
        if (inetAddress != null) {
            spbillCreateIp = inetAddress.getHostAddress();
        }
        paramsMap.put("spbill_create_ip", spbillCreateIp);
        log.info("paramsMap:{}"+paramsMap);
        Map<String,String> resp = wxPay.unifiedOrder(paramsMap);
        log.info("reponseMap:{}",resp);
        if (resp.get("result_code") != null && "SUCCESS".equals(resp.get("result_code"))) {
            String prepayid = resp.get("prepay_id");
            nonce_str = resp.get("nonce_str");
            log.info("nonce_str:{}",nonce_str);
            log.info("prepayid:{}",prepayid);
            // 二次加签开始
            /**
             * 	巨坑描述: 微信的二次加签是真的超级坑的,文档的描述很简单,我加签要那
             *  些那些参数,具体怎么要,你猜,参数key? 你继续猜.我猜了..不,你猜错了.
             *  官方文档上写的是驼峰要求的,实际编码却需要这种全小写的,也是坑
             *  死人不偿命的那种.这么大公司,缺这维护文档的五毛钱吗?
             * 如果从上看下来的,就会发现不同.一次加签,使用的是下划线,
             *  二次加签必须使用全小写的key,要不也可以加签成功,并且使用sign验证工具
             *  检查也是可以通过验证的.这就有点麻爪了.本人就被此处的问题,卡了6个小
             *  时,一脸懵逼.很自信的对客户端的同学说,我的sign没问题,我在官网都验证了
             *  ,但是客户端同学就是调不起来微信,一直返回-1.
             *  另外,需要注意的一个点就是,最终给客户端返回的Sign不能是第一次加签
             *  返回的sign值,是必须进行二次加签后的Sign.
             *
             **/
            //AppId和上面的一致
            newData.put("appid", tenpayConfig.getAppId());
            //订单号和上面的一致
            newData.put("noncestr", nonce_str);
            //还是要写死
            newData.put("package","Sign=WXPay");
            //商户号和上面的一致
            newData.put("partnerid",tenpayConfig.getMchId());
            //这个是微信返回的预支付订单号
            newData.put("prepayid",prepayid );
            //新的时间戳:要10位的长度.切记
            newData.put("timestamp",String.valueOf(new Date().getTime() / 1000));
            log.info("newData:{}",newData);
            //和上面的签名方式一样,也是调用微信支付的一个工具类直接生成的
            String wxUyilSign = WXPayUtil.generateSignature(newData, tenpayConfig.getKey(), WXPayConstants.SignType.MD5);
            log.info("paySign:{}",wxUyilSign);
            //开始封装给客户端返回的结果
            newMap.put("appid", tenpayConfig.getAppId());
            newMap.put("partnerid",tenpayConfig.getMchId());
            long time = new Date().getTime() / 1000;
            newMap.put("timestamp",time);
            newMap.put("noncestr", nonce_str);
            newMap.put("prepayid", prepayid);
            newMap.put("package","Sign=WXPay");
            newMap.put("sign",wxUyilSign);
        } else {
            throw new Exception("签名错误");
        }
        return newMap;
    }


    @Override
    public Result updateOrder(ShOrder shOrder) {
        shOrderDao.update(shOrder);
        return Result.ok("修改成功");
    }

    public Result market(String number) {
        String SS =RealUtil.market(number);
        JSONObject jsonObject =JSONObject.parseObject(SS);
        return Result.ok(jsonObject);
    }

}
